package com.ybkj.daijia.serverUtils;

import com.ybkj.daijia.Setting;
import com.ybkj.daijia.WxSetting;
import com.ybkj.daijia.server.Constant;
import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.io.FileOutputStream;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import org.apache.commons.lang3.StringUtils;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.context.annotation.Scope;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Component;

@Component
@Scope("singleton")
public class SettingUtils {

    @Autowired
    private CacheManager cacheManager;

    public static void main(String[] args) {
        new SettingUtils().get();
    }

    public WxSetting getWx() {

        WxSetting setting = null;

        Cache cache = cacheManager.getCache("setting");

        if (null != cache) {
            Cache.ValueWrapper obj = cache.get(Constant.SETTING_WX_CACHE_KEY);
            if (null != obj) {
                setting = (WxSetting) obj.get();

                return setting;
            }
        }

        setting = new WxSetting();

        Resource resource = new ClassPathResource("wxsetting.xml");

        SAXReader reader = new SAXReader();

        try {
            Document doc = reader.read(resource.getInputStream());

            @SuppressWarnings("unchecked")
            Iterator<Element> iter = doc.getRootElement().elementIterator("set");

            while (iter.hasNext()) {
                Element node = iter.next();
                String name = node.attributeValue("name");
                String value = node.attributeValue("value");

                Field field = WxSetting.class.getDeclaredField(name);
                field.setAccessible(true);
                field.set(setting, value);
            }

        } catch (Exception e) {
            e.printStackTrace();
        }

        cache.put(Constant.SETTING_WX_CACHE_KEY, setting);

        return setting;
    }

    public void setWx(WxSetting setting) {

        Cache cache = cacheManager.getCache("setting");

        Resource resource = new ClassPathResource("wxsetting.xml");
        SAXReader reader = new SAXReader();
        try {
            Document doc = reader.read(resource.getInputStream());
            @SuppressWarnings("unchecked")
            Iterator<Element> iter = doc.getRootElement().elementIterator();

            while (iter.hasNext()) {

                Element node = iter.next();

                String name = node.attributeValue("name");
                Field field = WxSetting.class.getDeclaredField(name);
                field.setAccessible(true);
                String value = (String) field.get(setting);
                if (null == value) {
                    value = StringUtils.EMPTY;
                }
                node.attribute("value").setValue(value);

                OutputFormat of = OutputFormat.createPrettyPrint();
                of.setEncoding("UTF-8");
                of.setIndent(true);
                of.setIndent("\t");
                of.setNewlines(true);

                XMLWriter writer = new XMLWriter(new FileOutputStream(resource.getFile()), of);
                writer.write(doc);
                writer.flush();
                writer.close();
            }

            cache.put(Constant.SETTING_WX_CACHE_KEY, setting);

        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    public void set(Setting setting) {
        Class clz = setting.getClass();
        Map<String, Field> fieldMap = new HashMap<>();
        for (Field field : clz.getDeclaredFields()) {
            String name = field.getName();
            fieldMap.put(name, field);
        }
        SAXReader reader = new SAXReader();
        Resource resource = new ClassPathResource("setting.xml");
        try {
            Document doc = reader.read(resource.getInputStream());

            @SuppressWarnings("unchecked")
            Iterator<Element> iter = doc.getRootElement().elementIterator();

            while (iter.hasNext()) {
                Element element = iter.next();
                String name = element.getName();
                String value = element.getTextTrim();
                Field field = fieldMap.get(name);
                if (field == null) {
                    continue;
                }
                field.setAccessible(true);
                Object ov = field.get(setting);
                if (ov != null) {
                    element.setText(String.valueOf(ov));
                }
            }
            OutputFormat of = OutputFormat.createPrettyPrint();
            of.setEncoding("UTF-8");
            of.setIndent(true);
            of.setIndent("\t");
            of.setNewlines(true);
            XMLWriter writer = new XMLWriter(new FileOutputStream(resource.getFile()), of);
            writer.write(doc);
            writer.flush();
            writer.close();
            Cache cache = cacheManager.getCache("setting");
            cache.put(Constant.SETTING_CACHE_KEY, setting);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public Setting get() {
        Setting setting = null;
        Cache cache = cacheManager.getCache("setting");
        if (null != cache) {
            Cache.ValueWrapper obj = cache.get(Constant.SETTING_CACHE_KEY);
            if (null != obj) {
                setting = (Setting) obj.get();
                if (setting != null) {
                    return setting;
                }
            }
        }
        setting = new Setting();
        Class clz = setting.getClass();
        readXml(setting, clz, "setting.xml");
        return setting;
    }

    public void readXml(Object o, Class clz, String path) {

        Map<String, Field> fieldMap = new HashMap<>();
        for (Field field : clz.getDeclaredFields()) {
            String name = field.getName();
            fieldMap.put(name, field);
        }
        SAXReader reader = new SAXReader();
        Resource resource = new ClassPathResource(path);
        try {
            Document doc = reader.read(resource.getInputStream());

            @SuppressWarnings("unchecked")
            Iterator<Element> iter = doc.getRootElement().elementIterator();

            while (iter.hasNext()) {
                Element element = iter.next();
                String name = element.getName();
                String value = element.getTextTrim();
                Field field = fieldMap.get(name);
                if (field == null) {
                    continue;
                }
                PropertyDescriptor pd = null;
                try {
                    pd = new PropertyDescriptor(field.getName(), clz);
                } catch (IntrospectionException e) {
                    continue;
                }
                field.setAccessible(true);
                field.set(o, string2class(value, field.getType()));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public <T> T string2class(String o, Class<T> clz) throws Exception {
        if (String.class.getName().equals(clz.getName())) {
            return (T) (Object) o;

        } else if (Integer.class.getName().equals(clz.getName())) {
            if (StringUtils.isBlank(o)) {
                return null;
            }
            return (T) (Object) Integer.valueOf(o);
        } else if (Double.class.getName().equals(clz.getName())) {
            if (StringUtils.isBlank(o)) {
                return null;
            }
            return (T) (Object) Double.valueOf(o);
        } else if (double.class.getName().equals(clz.getName())) {
            if (StringUtils.isBlank(o)) {
                return (T) (Object) 0d;
            }
            return (T) (Object) Double.valueOf(o);
        } else if (boolean.class.getName().equals(clz.getName())) {
            if (StringUtils.isBlank(o)) {
                return (T) (Object) false;
            }
            return (T) (Object) Boolean.parseBoolean(o);
        } else if (int.class.getName().equals(clz.getName())) {
            if (StringUtils.isBlank(o)) {
                return (T) (Object) 0;
            }
            return (T) (Object) Integer.parseInt(o);
        } else if (BigDecimal.class.getName().equals(clz.getName())) {
            if (StringUtils.isBlank(o)) {
                return (T) (Object) BigDecimal.ZERO;
            }
            return (T) (Object) new BigDecimal(o);
        }
        return null;
    }

    public void setCacheManager(CacheManager cacheManager) {
        this.cacheManager = cacheManager;
    }
}